Sensor Fusion for Kinetis MCUs (ISSDK/KSDK version)
output_stream.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2016, NXP Semiconductor
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without modification,
6  * are permitted provided that the following conditions are met:
7  *
8  * o Redistributions of source code must retain the above copyright notice, this list
9  * of conditions and the following disclaimer.
10  *
11  * o Redistributions in binary form must reproduce the above copyright notice, this
12  * list of conditions and the following disclaimer in the documentation and/or
13  * other materials provided with the distribution.
14  *
15  * o Neither the name of Freescale Semiconductor, Inc. nor the names of its
16  * contributors may be used to endorse or promote products derived from this
17  * software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
23  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
26  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 /*! \file output_stream.c
32  \brief Implements streaming function for the status subsystem. See status.h
33 */
34 
35 #include "sensor_fusion.h" // top level magCal and sensor fusion interfaces
36 #include "control.h" // Command/Streaming interface - application specific
37 #include "debug.h" // for test purposes
38 #define MAXPACKETRATEHZ 40
39 #define RATERESOLUTION 1000
40 
41 ///////////////////////////////////////////////////////////////////////////////////////////////////////
42 
43 // UART packet drivers
44 ///////////////////////////////////////////////////////////////////////////////////////////////////////
45 // function appends a variable number of source bytes to a destimation buffer
46 // for transmission as the bluetooth packet
47 // bluetooth packets are delimited by inserting the special byte 0x7E at the start
48 // and end of packets. this function must therefore handle the case of 0x7E appearing
49 // as general data. this is done here with the substitutions:
50 // a) replace 0x7E by 0x7D and 0x5E (one byte becomes two)
51 // b) replace 0x7D by 0x7D and 0x5D (one byte becomes two)
52 // the inverse mapping must be performed at the application receiving the bluetooth stream: ie:
53 // replace 0x7D and 0x5E with 0x7E
54 // replace 0x7D and 0x5D with 0x7D
55 // NOTE: do not use this function to append the start and end bytes 0x7E to the bluetooth
56 // buffer. instead add the start and end bytes 0x7E explicitly as in:
57 
58 // sUARTOutputBuffer[iByteCount++] = 0x7E;
59 void sBufAppendItem(uint8_t *pDest, uint16_t *pIndex, uint8_t *pSource,
60  uint16_t iBytesToCopy)
61 {
62  uint16_t i; // loop counter
63 
64  // loop over number of bytes to add to the destination buffer
65  for (i = 0; i < iBytesToCopy; i++)
66  {
67  switch (pSource[i])
68  {
69  case 0x7E:
70  // special case 1: replace 0x7E (start and end byte) with 0x7D and 0x5E
71  pDest[(*pIndex)++] = 0x7D;
72  pDest[(*pIndex)++] = 0x5E;
73  break;
74 
75  case 0x7D:
76  // special case 2: replace 0x7D with 0x7D and 0x5D
77  pDest[(*pIndex)++] = 0x7D;
78  pDest[(*pIndex)++] = 0x5D;
79  break;
80 
81  default:
82  // general case, simply add this byte without change
83  pDest[(*pIndex)++] = pSource[i];
84  break;
85  }
86  }
87 
88  return;
89 }
90 
91 // utility function for sending int16_t zeros
92 void sBufAppendZeros(uint8_t *pDest, uint16_t *pIndex, uint16_t numZeros) {
93  int16_t scratch16 = 0;
94  uint16_t i;
95  for (i=0; i<numZeros; i++) {
96  sBufAppendItem(pDest, pIndex, (uint8_t *) &scratch16, 2);
97  }
98 }
99 // utility function for reading common algorithm parameters
100 void readCommon( SV_ptr data,
101  Quaternion *fq,
102  int16_t *iPhi,
103  int16_t *iThe,
104  int16_t *iRho,
105  int16_t iOmega[],
106  uint16_t *isystick) {
107  *fq = data->fq;
108  iOmega[CHX] = (int16_t) (data->fOmega[CHX] * 20.0F);
109  iOmega[CHY] = (int16_t) (data->fOmega[CHY] * 20.0F);
110  iOmega[CHZ] = (int16_t) (data->fOmega[CHZ] * 20.0F);
111  *iPhi = (int16_t) (10.0F * data->fPhi);
112  *iThe = (int16_t) (10.0F * data->fThe);
113  *iRho = (int16_t) (10.0F * data->fRho);
114  *isystick = (uint16_t) (data->systick / 20);
115 }
116 
117 // throttle back by fractional multiplier
118 /// (OVERSAMPLE_RATIO * MAXPACKETRATEHZ) / SENSORFS
119 uint16_t throttle()
120 {
121  static int32 iThrottle = 0;
122  uint8_t skip;
123  // The UART (serial over USB and over Bluetooth)
124  // is limited to 115kbps which is more than adequate for the 31kbps
125  // needed at the default 25Hz output rate but insufficient for 100Hz or
126  // 200Hz output rates. There is little point is providing output data
127  // faster than 25Hz video rates but since the UARTs can
128  // support a higher rate, the limit is set to MAXPACKETRATEHZ=40Hz.
129 
130  // the increment applied to iThrottle is in the range 0 to (RATERESOLUTION - 1)
131  iThrottle += ((int32) MAXPACKETRATEHZ * (int32) RATERESOLUTION) / (int32) FUSION_HZ;
132  if (iThrottle >= RATERESOLUTION) {
133  // update the throttle counter and transmit the packets over UART (USB and Bluetooth)
134  iThrottle -= RATERESOLUTION;
135  skip = false;
136  } else {
137  skip = true;
138  }
139  return(skip);
140 }
141 
142 // set packets out over UART_A to shield / Bluetooth module and over UART_B to OpenSDA / USB
143 #pragma diag_suppress=Pe177,Pe550 // Suppress "never used" and "set but never used"
145 {
146  Quaternion fq; // quaternion to be transmitted
147  float ftmp; // scratch
148  static uint32_t iTimeStamp = 0; // 1MHz time stamp
149  uint16_t iIndex; // output buffer counter
150  int32_t scratch32; // scratch int32_t
151  int16_t scratch16; // scratch int16_t
152  int16_t iPhi,
153  iThe,
154  iRho; // integer angles to be transmitted
155  int16_t iDelta; // magnetic inclination angle if available
156  int16_t iOmega[3]; // scaled angular velocity vector
157  uint16_t isystick; // algorithm systick time
158  int16_t i, j, k; // general purpose
159  uint8_t tmpuint8_t; // scratch uint8_t
160  uint8_t flags; // byte of flags
161  uint8_t AngularVelocityPacketOn,
162  DebugPacketOn,
163  RPCPacketOn;
164  int8_t AccelCalPacketOn;
165  static uint8_t iPacketNumber = 0; // packet number
166 
167  // update the 1MHz time stamp counter expected by the PC GUI (independent of project clock rates)
168  iTimeStamp += 1000000 / FUSION_HZ;
169 
170 #if (MAXPACKETRATEHZ < FUSION_HZ)
171  uint8_t skip_packet = throttle(); // possible UART bandwidth problem
172  if (skip_packet) return; // need to skip packet transmission to avoid UART overrun
173 #endif
174 
175  // cache local copies of control flags so we don't have to keep dereferencing pointers below
176  quaternion_type quaternionPacketType;
177  quaternionPacketType = sfg->pControlSubsystem->QuaternionPacketType;
178  AngularVelocityPacketOn = sfg->pControlSubsystem->AngularVelocityPacketOn;
179  DebugPacketOn = sfg->pControlSubsystem->DebugPacketOn;
180  RPCPacketOn = sfg->pControlSubsystem->RPCPacketOn;
181  AccelCalPacketOn = sfg->pControlSubsystem->AccelCalPacketOn;
182 
183  // zero the counter for bytes accumulated into the transmit buffer
184  iIndex = 0;
185 
186  // ************************************************************************
187  // Main type 1: range 0 to 35 = 36 bytes
188  // Debug type 2: range 0 to 7 = 8 bytes
189  // Angular velocity type 3: range 0 to 13 = 14 bytes
190  // Euler angles type 4: range 0 to 13 = 14 bytes
191  // Altitude/Temp type 5: range 0 to 13 = 14 bytes
192  // Magnetic type 6: range 0 to 16 = 18 bytes
193  // Kalman packet 7: range 0 to 47 = 48 bytes
194  // Precision Accelerometer packet 8: range 0 to 46 = 47 bytes
195  //
196  // Total excluding intermittent packet 8 is:
197  // 152 bytes vs 256 bytes size of sUARTOutputBuffer
198  // at 25Hz, data rate is 25*152 = 3800 bytes/sec = 38.0kbaud = 33% of 115.2kbaud
199  // at 40Hz, data rate is 40*152 = 6080 bytes/sec = 60.8kbaud = 53% of 115.2kbaud
200  // at 50Hz, data rate is 50*152 = 7600 bytes/sec = 76.0kbaud = 66% of 115.2kbaud
201  // ************************************************************************
202  // ************************************************************************
203  // fixed length packet type 1
204  // this packet type is always transmitted
205  // total size is 0 to 35 equals 36 bytes
206  // ************************************************************************
207  // [0]: packet start byte (need a iIndex++ here since not using sBufAppendItem)
208  sUARTOutputBuffer[iIndex++] = 0x7E;
209 
210  // [1]: packet type 1 byte (iIndex is automatically updated in sBufAppendItem)
211  tmpuint8_t = 0x01;
212  sBufAppendItem(sUARTOutputBuffer, &iIndex, &tmpuint8_t, 1);
213 
214  // [2]: packet number byte
215  sBufAppendItem(sUARTOutputBuffer, &iIndex, &iPacketNumber, 1);
216  iPacketNumber++;
217 
218  // [6-3]: 1MHz time stamp (4 bytes)
219  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &iTimeStamp, 4);
220 
221  // [12-7]: integer accelerometer data words (scaled to 8192 counts per g for PC GUI)
222  // send non-zero data only if the accelerometer sensor is enabled and used by the selected quaternion
223  if (sfg->iFlags & F_USING_ACCEL) {
224  switch (quaternionPacketType)
225  {
226  case Q3:
227  case Q6MA:
228  case Q6AG:
229  case Q9:
230 #if F_USING_ACCEL
231  // accelerometer data is used for the selected quaternion so transmit but clip at 4g
232  scratch32 = (sfg->Accel.iGc[CHX] * 8192) / sfg->Accel.iCountsPerg;
233  if (scratch32 > 32767) scratch32 = 32767;
234  if (scratch32 < -32768) scratch32 = -32768;
235  scratch16 = (int16_t) (scratch32);
236  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
237 
238  scratch32 = (sfg->Accel.iGc[CHY] * 8192) / sfg->Accel.iCountsPerg;
239  if (scratch32 > 32767) scratch32 = 32767;
240  if (scratch32 < -32768) scratch32 = -32768;
241  scratch16 = (int16_t) (scratch32);
242  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
243 
244  scratch32 = (sfg->Accel.iGc[CHZ] * 8192) / sfg->Accel.iCountsPerg;
245  if (scratch32 > 32767) scratch32 = 32767;
246  if (scratch32 < -32768) scratch32 = -32768;
247  scratch16 = (int16_t) (scratch32);
248  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
249  break;
250 #endif // F_USING_ACCEL
251  case Q3M:
252  case Q3G:
253  default:
254  // accelerometer data is not used in currently selected algorithm so transmit zero
255  sBufAppendZeros(sUARTOutputBuffer, &iIndex, 3);
256  break;
257  }
258  } else {
259  // accelerometer structure is not defined so transmit zero
260  sBufAppendZeros(sUARTOutputBuffer, &iIndex, 3);
261  }
262  // [18-13]: integer calibrated magnetometer data words (already scaled to 10 count per uT for PC GUI)
263  // send non-zero data only if the magnetometer sensor is enabled and used by the selected quaternion
264  if (sfg->iFlags & F_USING_MAG)
265  switch (quaternionPacketType)
266  {
267  case Q3M:
268  case Q6MA:
269  case Q9:
270 #if F_USING_MAG
271  // magnetometer data is used for the selected quaternion so transmit
272  scratch16 = (int16_t) (sfg->Mag.iBc[CHX] * 10) / (sfg->Mag.iCountsPeruT);
273  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
274  scratch16 = (int16_t) ((sfg->Mag.iBc[CHY] * 10) / sfg->Mag.iCountsPeruT);
275  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
276  scratch16 = (int16_t) ((sfg->Mag.iBc[CHZ] * 10) / sfg->Mag.iCountsPeruT);
277  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
278  break;
279 #endif
280  // magnetometer data is not used in currently selected algorithm so transmit zero
281  case Q3:
282  case Q3G:
283  case Q6AG:
284  default:
285  sBufAppendZeros(sUARTOutputBuffer, &iIndex, 3);
286  break;
287  }
288  else
289  {
290  // magnetometer structure is not defined so transmit zero
291  sBufAppendZeros(sUARTOutputBuffer, &iIndex, 3);
292  }
293 
294  // [24-19]: uncalibrated gyro data words (scaled to 20 counts per deg/s for PC GUI)
295  // send non-zero data only if the gyro sensor is enabled and used by the selected quaternion
296  if (sfg->iFlags & F_USING_GYRO)
297  {
298  switch (quaternionPacketType)
299  {
300  case Q3G:
301  case Q6AG:
302 #if F_USING_GYRO
303  case Q9:
304 
305  // gyro data is used for the selected quaternion so transmit
306  scratch16 = (int16_t) ((sfg->Gyro.iYs[CHX] * 20) / sfg->Gyro.iCountsPerDegPerSec);
307  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
308  scratch16 = (int16_t) ((sfg->Gyro.iYs[CHY] * 20) / sfg->Gyro.iCountsPerDegPerSec);
309  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
310  scratch16 = (int16_t) ((sfg->Gyro.iYs[CHZ] * 20) / sfg->Gyro.iCountsPerDegPerSec);
311  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
312  break;
313 #endif
314  case Q3:
315  case Q3M:
316  case Q6MA:
317  default:
318  // gyro data is not used in currently selected algorithm so transmit zero
319  sBufAppendZeros(sUARTOutputBuffer, &iIndex, 3);
320  break;
321  }
322  }
323  else
324  {
325  // gyro structure is not defined so transmit zero
326  sBufAppendZeros(sUARTOutputBuffer, &iIndex, 3);
327  }
328 
329  // initialize default quaternion, flags byte, angular velocity and orientation
330  fq.q0 = 1.0F;
331  fq.q1 = fq.q2 = fq.q3 = 0.0F;
332  flags = 0x00;
333  iOmega[CHX] = iOmega[CHY] = iOmega[CHZ] = 0;
334  iPhi = iThe = iRho = iDelta = 0;
335  isystick = 0;
336 
337  // flags byte 33: quaternion type in least significant nibble
338  // Q3: coordinate nibble, 1
339  // Q3M: coordinate nibble, 6
340  // Q3G: coordinate nibble, 3
341  // Q6MA: coordinate nibble, 2
342  // Q6AG: coordinate nibble, 4
343  // Q9: coordinate nibble, 8
344  // flags byte 33: coordinate in most significant nibble
345  // Aerospace/NED: 0, quaternion nibble
346  // Android: 1, quaternion nibble
347  // Windows 8: 2, quaternion nibble
348  // set the quaternion, flags, angular velocity and Euler angles
349  switch (quaternionPacketType)
350  {
351 #if F_3DOF_G_BASIC
352  case Q3:
353  if (sfg->iFlags & F_3DOF_G_BASIC)
354  {
355  flags |= 0x01;
356  readCommon((SV_ptr)&sfg->SV_3DOF_G_BASIC, &fq, &iPhi, &iThe, &iRho, iOmega, &isystick);
357  }
358  break;
359 #endif
360 #if F_3DOF_B_BASIC
361  case Q3M:
362  if (sfg->iFlags & F_3DOF_B_BASIC)
363  {
364  flags |= 0x06;
365  readCommon((SV_ptr)&sfg->SV_3DOF_B_BASIC, &fq, &iPhi, &iThe, &iRho, iOmega, &isystick);
366  }
367  break;
368 #endif
369 #if F_3DOF_Y_BASIC
370  case Q3G:
371  if (sfg->iFlags & F_3DOF_Y_BASIC)
372  {
373  flags |= 0x03;
374  readCommon((SV_ptr)&sfg->SV_3DOF_Y_BASIC, &fq, &iPhi, &iThe, &iRho, iOmega, &isystick);
375  }
376  break;
377 #endif
378 #if F_6DOF_GB_BASIC
379  case Q6MA:
380  if (sfg->iFlags & F_6DOF_GB_BASIC)
381  {
382  flags |= 0x02;
383  iDelta = (int16_t) (10.0F * sfg->SV_6DOF_GB_BASIC.fLPDelta);
384  readCommon((SV_ptr)&sfg->SV_6DOF_GB_BASIC, &fq, &iPhi, &iThe, &iRho, iOmega, &isystick);
385  }
386  break;
387 #endif
388 #if F_6DOF_GY_KALMAN
389  case Q6AG:
390  if (sfg->iFlags & F_6DOF_GY_KALMAN)
391  {
392  flags |= 0x04;
393  readCommon((SV_ptr)&sfg->SV_6DOF_GY_KALMAN, &fq, &iPhi, &iThe, &iRho, iOmega, &isystick);
394  }
395  break;
396 #endif
397 #if F_9DOF_GBY_KALMAN
398  case Q9:
399  if (sfg->iFlags & F_9DOF_GBY_KALMAN)
400  {
401  flags |= 0x08;
402  iDelta = (int16_t) (10.0F * sfg->SV_9DOF_GBY_KALMAN.fDeltaPl);
403  readCommon((SV_ptr)&sfg->SV_9DOF_GBY_KALMAN, &fq, &iPhi, &iThe, &iRho, iOmega, &isystick);
404  }
405  break;
406 #endif
407  default:
408  // use the default data already initialized
409  break;
410  }
411 
412  // [32-25]: scale the quaternion (30K = 1.0F) and add to the buffer
413  scratch16 = (int16_t) (fq.q0 * 30000.0F);
414  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
415  scratch16 = (int16_t) (fq.q1 * 30000.0F);
416  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
417  scratch16 = (int16_t) (fq.q2 * 30000.0F);
418  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
419  scratch16 = (int16_t) (fq.q3 * 30000.0F);
420  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
421 
422  // set the coordinate system bits in flags from default NED (00)
423 #if THISCOORDSYSTEM == ANDROID
424  // set the Android flag bits
425  flags |= 0x10;
426 #elif THISCOORDSYSTEM == WIN8
427  // set the Win8 flag bits
428  flags |= 0x20;
429 #endif // THISCOORDSYSTEM
430 
431  // [33]: add the flags byte to the buffer
432  sBufAppendItem(sUARTOutputBuffer, &iIndex, &flags, 1);
433 
434  // [34]: add the shield (bits 7-5) and Kinetis (bits 4-0) byte
435  tmpuint8_t = ((THIS_SHIELD & 0x07) << 5) | (THIS_BOARD & 0x1F);
436  sBufAppendItem(sUARTOutputBuffer, &iIndex, &tmpuint8_t, 1);
437 
438  // [35]: add the tail byte for the standard packet type 1
439  sUARTOutputBuffer[iIndex++] = 0x7E;
440 
441  // ************************************************************************
442  // Variable length debug packet type 2
443  // total size is 0 to 7 equals 8 bytes
444  // ************************************************************************
445  if (DebugPacketOn)
446  {
447  // [0]: packet start byte
448  sUARTOutputBuffer[iIndex++] = 0x7E;
449 
450  // [1]: packet type 2 byte
451  tmpuint8_t = 0x02;
452  sBufAppendItem(sUARTOutputBuffer, &iIndex, &tmpuint8_t, 1);
453 
454  // [2]: packet number byte
455  sBufAppendItem(sUARTOutputBuffer, &iIndex, &iPacketNumber, 1);
456  iPacketNumber++;
457 
458  // [4-3] software version number
459  scratch16 = THISBUILD;
460  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
461 
462  // [6-5] systick count / 20
463  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &isystick, 2);
464 
465  // [7 in practice but can be variable]: add the tail byte for the debug packet type 2
466  sUARTOutputBuffer[iIndex++] = 0x7E;
467  }
468 
469  // ************************************************************************
470  // Angular Velocity packet type 3
471  // total bytes for packet type 2 is range 0 to 13 = 14 bytes
472  // ************************************************************************
473  if (AngularVelocityPacketOn)
474  {
475  // [0]: packet start byte
476  sUARTOutputBuffer[iIndex++] = 0x7E;
477 
478  // [1]: packet type 3 byte (angular velocity)
479  tmpuint8_t = 0x03;
480  sBufAppendItem(sUARTOutputBuffer, &iIndex, &tmpuint8_t, 1);
481 
482  // [2]: packet number byte
483  sBufAppendItem(sUARTOutputBuffer, &iIndex, &iPacketNumber, 1);
484  iPacketNumber++;
485 
486  // [6-3]: time stamp (4 bytes)
487  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &iTimeStamp, 4);
488 
489  // [12-7]: add the scaled angular velocity vector to the output buffer
490  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &iOmega[CHX], 2);
491  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &iOmega[CHY], 2);
492  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &iOmega[CHZ], 2);
493 
494  // [13]: add the tail byte for the angular velocity packet type 3
495  sUARTOutputBuffer[iIndex++] = 0x7E;
496  }
497 
498  // ************************************************************************
499  // Roll, Pitch, Compass Euler angles packet type 4
500  // total bytes for packet type 4 is range 0 to 13 = 14 bytes
501  // ************************************************************************
502  if (RPCPacketOn)
503  {
504  // [0]: packet start byte
505  sUARTOutputBuffer[iIndex++] = 0x7E;
506 
507  // [1]: packet type 4 byte (Euler angles)
508  tmpuint8_t = 0x04;
509  sBufAppendItem(sUARTOutputBuffer, &iIndex, &tmpuint8_t, 1);
510 
511  // [2]: packet number byte
512  sBufAppendItem(sUARTOutputBuffer, &iIndex, &iPacketNumber, 1);
513  iPacketNumber++;
514 
515  // [6-3]: time stamp (4 bytes)
516  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &iTimeStamp, 4);
517 
518  // [12-7]: add the angles (resolution 0.1 deg per count) to the transmit buffer
519  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &iPhi, 2);
520  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &iThe, 2);
521  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &iRho, 2);
522 
523  // [13]: add the tail byte for the roll, pitch, compass angle packet type 4
524  sUARTOutputBuffer[iIndex++] = 0x7E;
525  }
526 
527  // ************************************************************************
528  // Altitude / Temperature packet type 5
529  // total bytes for packet type 5 is range 0 to 13 = 14 bytes
530  // ************************************************************************
531 #if F_USING_PRESSURE
532  if (sfg->iFlags & F_1DOF_P_BASIC)
533  {
534  if (sfg->pControlSubsystem->AltPacketOn && sfg->Pressure.iWhoAmI)
535  {
536  // [0]: packet start byte
537  sUARTOutputBuffer[iIndex++] = 0x7E;
538 
539  // [1]: packet type 5 byte
540  tmpuint8_t = 0x05;
541  sBufAppendItem(sUARTOutputBuffer, &iIndex, &tmpuint8_t, 1);
542 
543  // [2]: packet number byte
544  sBufAppendItem(sUARTOutputBuffer, &iIndex, &iPacketNumber, 1);
545  iPacketNumber++;
546 
547  // [6-3]: time stamp (4 bytes)
548  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &iTimeStamp,
549  4);
550 
551  // [10-7]: altitude (4 bytes, metres times 1000)
552  scratch32 = (int32_t) (sfg->SV_1DOF_P_BASIC.fLPH * 1000.0F);
553  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch32, 4);
554 
555  // [12-11]: temperature (2 bytes, deg C times 100)
556  scratch16 = (int16_t) (sfg->SV_1DOF_P_BASIC.fLPT * 100.0F);
557  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
558 
559  // [13]: add the tail byte for the altitude / temperature packet type 5
560  sUARTOutputBuffer[iIndex++] = 0x7E;
561  }
562  }
563 #endif
564 
565  // ************************************************************************
566  // magnetic buffer packet type 6
567  // currently total size is 0 to 17 equals 18 bytes
568  // this packet is only transmitted if a magnetic algorithm is computed
569  // ************************************************************************
570 #if F_USING_MAG
571  static int16_t MagneticPacketID = 0; // magnetic packet number
572  if (sfg->iFlags & F_USING_MAG)
573  {
574  // [0]: packet start byte
575  sUARTOutputBuffer[iIndex++] = 0x7E;
576 
577  // [1]: packet type 6 byte
578  tmpuint8_t = 0x06;
579  sBufAppendItem(sUARTOutputBuffer, &iIndex, &tmpuint8_t, 1);
580 
581  // [2]: packet number byte
582  sBufAppendItem(sUARTOutputBuffer, &iIndex, &iPacketNumber, 1);
583  iPacketNumber++;
584 
585  // [4-3]: number of active measurements in the magnetic buffer
586  sBufAppendItem(sUARTOutputBuffer, &iIndex,
587  (uint8_t *) &(sfg->MagBuffer.iMagBufferCount), 2);
588 
589  // [6-5]: fit error (%) with resolution 0.01%
590  if (sfg->MagCal.fFitErrorpc > 327.67F)
591  scratch16 = 32767;
592  else
593  scratch16 = (int16_t) (sfg->MagCal.fFitErrorpc * 100.0F);
594  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
595 
596  // [8-7]: geomagnetic field strength with resolution 0.1uT
597  scratch16 = (int16_t) (sfg->MagCal.fB * 10.0F);
598  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
599 
600  // always calculate magnetic buffer row and column (low overhead and saves warnings)
601  k = MagneticPacketID - 10;
602  j = k / MAGBUFFSIZEX;
603  i = k - j * MAGBUFFSIZEX;
604 
605  // [10-9]: int16_t: ID of magnetic variable to be transmitted
606  // ID 0 to 4 inclusive are magnetic calibration coefficients
607  // ID 5 to 9 inclusive are for future expansion
608  // ID 10 to (MAGBUFFSIZEX=12) * (MAGBUFFSIZEY=24)-1 or 10 to 10+288-1 are magnetic buffer elements
609  // where the convention is used that a negative value indicates empty buffer element (index=-1)
610  if ((MagneticPacketID >= 10) && (sfg->MagBuffer.index[i][j] == -1))
611  {
612  // use negative ID to indicate inactive magnetic buffer element
613  scratch16 = -MagneticPacketID;
614  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
615  }
616  else
617  {
618  // use positive ID unchanged for variable or active magnetic buffer entry
619  scratch16 = MagneticPacketID;
620  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
621  }
622 
623  // [12-11]: int16_t: variable 1 to be transmitted this iteration
624  // [14-13]: int16_t: variable 2 to be transmitted this iteration
625  // [16-15]: int16_t: variable 3 to be transmitted this iteration
626  switch (MagneticPacketID)
627  {
628  case 0:
629  // item 1: currently unused
630  scratch16 = 0;
631  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
632 
633  // item 2: currently unused
634  scratch16 = 0;
635  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
636 
637  // item 3: magnetic inclination angle with resolution 0.1 deg
638  scratch16 = iDelta;
639  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
640  break;
641 
642  case 1:
643  // items 1 to 3: hard iron components range -3276uT to +3276uT encoded with 0.1uT resolution
644  scratch16 = (int16_t) (sfg->MagCal.fV[CHX] * 10.0F);
645  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
646  scratch16 = (int16_t) (sfg->MagCal.fV[CHY] * 10.0F);
647  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
648  scratch16 = (int16_t) (sfg->MagCal.fV[CHZ] * 10.0F);
649  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
650  break;
651 
652  case 2:
653  // items 1 to 3: diagonal soft iron range -32. to +32. encoded with 0.001 resolution
654  scratch16 = (int16_t) (sfg->MagCal.finvW[CHX][CHX] * 1000.0F);
655  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
656  scratch16 = (int16_t) (sfg->MagCal.finvW[CHY][CHY] * 1000.0F);
657  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
658  scratch16 = (int16_t) (sfg->MagCal.finvW[CHZ][CHZ] * 1000.0F);
659  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
660  break;
661 
662  case 3:
663  // items 1 to 3: off-diagonal soft iron range -32. to +32. encoded with 0.001 resolution
664  scratch16 = (int16_t) (sfg->MagCal.finvW[CHX][CHY] * 1000.0F);
665  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
666  scratch16 = (int16_t) (sfg->MagCal.finvW[CHX][CHZ] * 1000.0F);
667  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
668  scratch16 = (int16_t) (sfg->MagCal.finvW[CHY][CHZ] * 1000.0F);
669  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
670  break;
671 
672  case 4:
673  case 5:
674  case 6:
675  case 7:
676  case 8:
677  case 9:
678  // cases 4 to 9 inclusive are for future expansion so transmit zeroes for now
679  sBufAppendZeros(sUARTOutputBuffer, &iIndex, 3);
680  break;
681 
682  default:
683  // 10 and upwards: this handles the magnetic buffer elements
684  sBufAppendItem(sUARTOutputBuffer, &iIndex,
685  (uint8_t *) &(sfg->MagBuffer.iBs[CHX][i][j]), 2);
686  sBufAppendItem(sUARTOutputBuffer, &iIndex,
687  (uint8_t *) &(sfg->MagBuffer.iBs[CHY][i][j]), 2);
688  sBufAppendItem(sUARTOutputBuffer, &iIndex,
689  (uint8_t *) &(sfg->MagBuffer.iBs[CHZ][i][j]), 2);
690  break;
691  }
692 
693  // wrap the variable ID back to zero if necessary
694  MagneticPacketID++;
695  if (MagneticPacketID >= (10 + MAGBUFFSIZEX * MAGBUFFSIZEY))
696  MagneticPacketID = 0;
697 
698  // [17]: add the tail byte for the magnetic packet type 6
699  sUARTOutputBuffer[iIndex++] = 0x7E;
700  }
701 #endif
702 
703  // *******************************************************************************
704  // Kalman filter packet type 7
705  // total bytes for packet type 7 is range 0 to 41 inclusive = 42 bytes
706  // this packet is only transmitted when a Kalman algorithm is computed
707  // and then non-zero data is transmitted only when a Kalman quaternion is selected
708  // *******************************************************************************
709  bool kalman = false;
710 #if F_6DOF_GY_KALMAN
711  uint8_t six_axis_kalman = (sfg->iFlags & F_6DOF_GY_KALMAN) && (quaternionPacketType == Q6AG);
712  kalman = six_axis_kalman;
713 #endif
714 #if F_9DOF_GBY_KALMAN
715  uint8_t nine_axis_kalman = (sfg->iFlags & F_9DOF_GBY_KALMAN) && (quaternionPacketType == Q9);
716  kalman = kalman | nine_axis_kalman;
717 #endif
718 #if F_6DOF_GY_KALMAN || F_9DOF_GBY_KALMAN
719  if (kalman)
720  {
721  if ((quaternionPacketType == Q6AG) || (quaternionPacketType == Q9))
722  {
723  // [0]: packet start byte
724  sUARTOutputBuffer[iIndex++] = 0x7E;
725 
726  // [1]: packet type 7 byte
727  tmpuint8_t = 0x07;
728  sBufAppendItem(sUARTOutputBuffer, &iIndex, &tmpuint8_t, 1);
729 
730  // [2]: packet number byte
731  sBufAppendItem(sUARTOutputBuffer, &iIndex, &iPacketNumber, 1);
732  iPacketNumber++;
733 
734  // [4-3]: fzgErr[CHX] resolution scaled by 30000
735  // [6-5]: fzgErr[CHY] resolution scaled by 30000
736  // [8-7]: fzgErr[CHZ] resolution scaled by 30000
737  for (i = CHX; i <= CHZ; i++)
738  {
739 #if F_6DOF_GY_KALMAN
740  if (six_axis_kalman) scratch16 = (int16_t) (sfg->SV_6DOF_GY_KALMAN.fZErr[i] * 30000.0F);
741 #endif
742 #if F_9DOF_GBY_KALMAN
743  if (nine_axis_kalman) scratch16 = (int16_t) (sfg->SV_9DOF_GBY_KALMAN.fZErr[i] * 30000.0F);
744 #endif
745  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16,2);
746  }
747 
748  // [10-9]: fgErrPl[CHX] resolution scaled by 30000
749  // [12-11]: fgErrPl[CHY] resolution scaled by 30000
750  // [14-13]: fgErrPl[CHZ] resolution scaled by 30000
751  for (i = CHX; i <= CHZ; i++)
752  {
753 #if F_6DOF_GY_KALMAN
754  if (six_axis_kalman) scratch16 = (int16_t) (sfg->SV_6DOF_GY_KALMAN.fqgErrPl[i] * 30000.0F);
755 #endif
756 #if F_9DOF_GBY_KALMAN
757  if (nine_axis_kalman) scratch16 = (int16_t) (sfg->SV_9DOF_GBY_KALMAN.fqgErrPl[i] * 30000.0F);
758 #endif
759  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16,2);
760  }
761 
762  // [16-15]: fzmErr[CHX] resolution scaled by 30000
763  // [18-17]: fzmErr[CHY] resolution scaled by 30000
764  // [20-19]: fzmErr[CHZ] resolution scaled by 30000
765  for (i = CHX; i <= CHZ; i++)
766  {
767 #if F_6DOF_GY_KALMAN
768  if (six_axis_kalman) scratch16 = 0;
769 #endif
770 #if F_9DOF_GBY_KALMAN
771  if (nine_axis_kalman) scratch16 = (int16_t) (sfg->SV_9DOF_GBY_KALMAN.fZErr[i + 3] * 30000.0F);
772 #endif
773  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
774  }
775 
776  // [22-21]: fmErrPl[CHX] resolution scaled by 30000
777  // [24-23]: fmErrPl[CHY] resolution scaled by 30000
778  // [26-25]: fmErrPl[CHZ] resolution scaled by 30000
779  for (i = CHX; i <= CHZ; i++)
780  {
781 #if F_6DOF_GY_KALMAN
782  if (six_axis_kalman) scratch16 = 0;
783 #endif
784 #if F_9DOF_GBY_KALMAN
785  if (nine_axis_kalman) scratch16 = (int16_t) (sfg->SV_9DOF_GBY_KALMAN.fqmErrPl[i] * 30000.0F);
786 #endif
787  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
788  }
789 
790  // [28-27]: fbPl[CHX] resolution 0.001 deg/sec
791  // [30-29]: fbPl[CHY] resolution 0.001 deg/sec
792  // [32-31]: fbPl[CHZ] resolution 0.001 deg/sec
793  for (i = CHX; i <= CHZ; i++)
794  {
795 #if F_6DOF_GY_KALMAN
796  if (six_axis_kalman) scratch16 = (int16_t) (sfg->SV_6DOF_GY_KALMAN.fbPl[i] * 1000.0F);
797 #endif
798 #if F_9DOF_GBY_KALMAN
799  if (nine_axis_kalman) scratch16 = (int16_t) (sfg->SV_9DOF_GBY_KALMAN.fbPl[i] * 1000.0F);
800 #endif
801  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
802  }
803 
804  // [34-33]: fDeltaPl resolution 0.01deg
805  scratch16 = 0;
806 #if F_9DOF_GBY_KALMAN
807  if (nine_axis_kalman) scratch16 = (int16_t) (sfg->SV_9DOF_GBY_KALMAN.fDeltaPl * 100.0F);
808 #endif
809  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
810 
811  // [36-35]: fAccGl[CHX] resolution 1/8192 g
812  // [38-37]: fAccGl[CHY] resolution 1/8192 g
813  // [40-39]: fAccGl[CHZ] resolution 1/8192 g
814  for (i = CHX; i <= CHZ; i++)
815  {
816  // default to zero data
817  ftmp = 0.0F;
818 #if F_6DOF_GY_KALMAN
819  if (six_axis_kalman) ftmp = sfg->SV_6DOF_GY_KALMAN.fAccGl[i] * 8192.0F;
820 #endif
821 #if F_9DOF_GBY_KALMAN
822  if (nine_axis_kalman) ftmp = sfg->SV_9DOF_GBY_KALMAN.fAccGl[i] * 8192.0F;
823 #endif
824 
825  // check for clipping
826  if (ftmp > 32767.0F) scratch16 = 32767;
827  else if (ftmp < -32768.0F) scratch16 = -32768;
828  else scratch16 = (int16_t) ftmp;
829  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
830  }
831 
832  // [42-41]: fDisGl[CHX] resolution 0.01m
833  // [44-43]: fDisGl[CHY] resolution 0.01m
834  // [46-45]: fDisGl[CHZ] resolution 0.01m
835  for (i = CHX; i <= CHZ; i++)
836  {
837  // default to zero data
838  ftmp = 0.0F;
839 #if F_9DOF_GBY_KALMAN
840  if (nine_axis_kalman) ftmp = sfg->SV_9DOF_GBY_KALMAN.fDisGl[i] * 100.0F;
841 #endif
842 
843  // check for clipping
844  if (ftmp > 32767.0F) scratch16 = 32767;
845  else if (ftmp < -32768.0F) scratch16 = -32768;
846  else scratch16 = (int16_t) ftmp;
847  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
848  }
849 
850  // [47]: add the tail byte for the Kalman packet type 7
851  sUARTOutputBuffer[iIndex++] = 0x7E;
852  }
853  } // end of check for Kalman packet
854 #endif
855 #if F_USING_ACCEL
856  // *************************************************************************
857  // fixed length packet type 8 transmitted whenever a precision accelerometer
858  // measurement has been stored.
859  // total size is 0 to 40 equals 41 bytes
860  // *************************************************************************
861  // check to see which packet (if any) is to be transmitted
862  if (AccelCalPacketOn != -1)
863  {
864  // [0]: packet start byte (need a iIndex++ here since not using sBufAppendItem)
865  sUARTOutputBuffer[iIndex++] = 0x7E;
866 
867  // [1]: packet type 8 byte (iIndex is automatically updated in sBufAppendItem)
868  tmpuint8_t = 0x08;
869  sBufAppendItem(sUARTOutputBuffer, &iIndex, &tmpuint8_t, 1);
870 
871  // [2]: packet number byte
872  sBufAppendItem(sUARTOutputBuffer, &iIndex, &iPacketNumber, 1);
873  iPacketNumber++;
874 
875  // [3]: AccelCalPacketOn in range 0-11 denotes stored location and MAXORIENTATIONS denotes transmit
876  // precision accelerometer calibration on power on before any measurements have been obtained.
877  sBufAppendItem(sUARTOutputBuffer, &iIndex,
878  (uint8_t *) &(AccelCalPacketOn), 1);
879 
880  // [9-4]: stored accelerometer measurement fGs (scaled to 8192 counts per g)
881  if ((AccelCalPacketOn >= 0) &&
882  (AccelCalPacketOn < MAX_ACCEL_CAL_ORIENTATIONS))
883  {
884  scratch16 = (int16_t) (sfg->AccelBuffer.fGsStored[AccelCalPacketOn][CHX] * 8192.0F);
885  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
886  scratch16 = (int16_t) (sfg->AccelBuffer.fGsStored[AccelCalPacketOn][CHY] * 8192.0F);
887  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
888  scratch16 = (int16_t) (sfg->AccelBuffer.fGsStored[AccelCalPacketOn][CHZ] * 8192.0F);
889  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
890  }
891  else
892  {
893  // transmit zero bytes since this is the power on or reset transmission of the precision calibration
894  sBufAppendZeros(sUARTOutputBuffer, &iIndex, 3);
895  }
896 
897  // [15-10]: precision accelerometer offset vector fV (g scaled by 32768.0)
898  scratch16 = (int16_t) (sfg->AccelCal.fV[CHX] * 32768.0F);
899  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
900  scratch16 = (int16_t) (sfg->AccelCal.fV[CHY] * 32768.0F);
901  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
902  scratch16 = (int16_t) (sfg->AccelCal.fV[CHZ] * 32768.0F);
903  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
904 
905  // [21-16]: precision accelerometer inverse gain matrix diagonal finvW - 1.0 (scaled by 10000.0)
906  scratch16 = (int16_t) ((sfg->AccelCal.finvW[CHX][CHX] - 1.0F) * 10000.0F);
907  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
908  scratch16 = (int16_t) ((sfg->AccelCal.finvW[CHY][CHY] - 1.0F) * 10000.0F);
909  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
910  scratch16 = (int16_t) ((sfg->AccelCal.finvW[CHZ][CHZ] - 1.0F) * 10000.0F);
911  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
912 
913  // [27-22]: precision accelerometer inverse gain matrix off-diagonal finvW (scaled by 10000)
914  scratch16 = (int16_t) (sfg->AccelCal.finvW[CHX][CHY] * 10000.0F);
915  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
916  scratch16 = (int16_t) (sfg->AccelCal.finvW[CHX][CHZ] * 10000.0F);
917  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
918  scratch16 = (int16_t) (sfg->AccelCal.finvW[CHY][CHZ] * 10000.0F);
919  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
920 
921  // [33-28]: precision accelerometer rotation matrix diagonal fR0 (scaled by 10000)
922  scratch16 = (int16_t) (sfg->AccelCal.fR0[CHX][CHX] * 10000.0F);
923  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
924  scratch16 = (int16_t) (sfg->AccelCal.fR0[CHY][CHY] * 10000.0F);
925  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
926  scratch16 = (int16_t) (sfg->AccelCal.fR0[CHZ][CHZ] * 10000.0F);
927  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
928 
929  // [45-34]: precision accelerometer inverse rotation matrix off-diagonal fR0 (scaled by 10000)
930  scratch16 = (int16_t) (sfg->AccelCal.fR0[CHX][CHY] * 10000.0F);
931  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
932  scratch16 = (int16_t) (sfg->AccelCal.fR0[CHX][CHZ] * 10000.0F);
933  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
934  scratch16 = (int16_t) (sfg->AccelCal.fR0[CHY][CHX] * 10000.0F);
935  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
936  scratch16 = (int16_t) (sfg->AccelCal.fR0[CHY][CHZ] * 10000.0F);
937  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
938  scratch16 = (int16_t) (sfg->AccelCal.fR0[CHZ][CHX] * 10000.0F);
939  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
940  scratch16 = (int16_t) (sfg->AccelCal.fR0[CHZ][CHY] * 10000.0F);
941  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
942 
943  // [46]: add the tail byte for the packet type 8
944  sUARTOutputBuffer[iIndex++] = 0x7E;
945 
946  // disable future packets of this type until a new measurement has been obtained
948  }
949 #endif // F_USING_ACCEL
950  // ********************************************************************************
951  // all packets have now been constructed in the output buffer so now transmit.
952  // The final iIndex++ gives the number of bytes to transmit which is one more than
953  // the last index in the buffer. this function is non-blocking
954  // ********************************************************************************
955  sfg->pControlSubsystem->write(sfg->pControlSubsystem, sUARTOutputBuffer, iIndex);
956  return;
957 }
enum quaternion quaternion_type
the quaternion type to be transmitted
float fThe
pitch (deg)
Quaternion derived from full 9-axis sensor fusion.
Definition: sensor_fusion.h:70
#define MAGBUFFSIZEX
x dimension in magnetometer buffer (12x24 equals 288 elements)
Definition: magnetic.h:44
#define F_USING_GYRO
nominally 0x0004 if a gyro is to be used, 0x0000 otherwise
#define CHY
Used to access Y-channel entries in various data data structures.
Definition: sensor_fusion.h:77
void readCommon(SV_ptr data, Quaternion *fq, int16_t *iPhi, int16_t *iThe, int16_t *iRho, int16_t iOmega[], uint16_t *isystick)
Quaternion fq
orientation quaternion
uint32_t iFlags
a bit-field of sensors and algorithms used
ApplyPerturbation function used to analyze dynamic performance.
float q0
scalar component
Definition: orientation.h:39
volatile uint8_t AltPacketOn
flag to enable altitude packet
Definition: control.h:70
Quaternion derived from 3-axis mag only (auto compass algorithm)
Definition: sensor_fusion.h:66
MagCalibration MagCal
mag cal storage
The top level fusion structure.
volatile int8_t AccelCalPacketOn
variable used to coordinate accelerometer calibration
Definition: control.h:71
float fOmega[3]
average angular velocity (deg/s)
float q3
z vector component
Definition: orientation.h:42
int16_t iMagBufferCount
number of magnetometer readings
Definition: magnetic.h:68
Quaternion derived from 3-axis gyro only (rotation)
Definition: sensor_fusion.h:67
int16_t iCountsPeruT
counts per uT
Quaternion derived from 3-axis accel + 3 axis mag (eCompass)
Definition: sensor_fusion.h:68
int32_t int32
Definition: sensor_fusion.h:57
#define MAXPACKETRATEHZ
Definition: output_stream.c:38
Quaternion derived from 3-axis accel + 3-axis gyro (gaming)
Definition: sensor_fusion.h:69
uint16_t throttle()
(OVERSAMPLE_RATIO * MAXPACKETRATEHZ) / SENSORFS
struct ControlSubsystem * pControlSubsystem
MagSensor Mag
magnetometer storage
quaternion structure definition
Definition: orientation.h:37
#define F_1DOF_P_BASIC
1DOF pressure (altitude) and temperature algorithm selector - 0x0100 to include, 0x0000 otherwise ...
#define F_9DOF_GBY_KALMAN
void sBufAppendItem(uint8_t *pDest, uint16_t *pIndex, uint8_t *pSource, uint16_t iBytesToCopy)
Utility function used to place data in output buffer about to be transmitted via UART.
Definition: output_stream.c:59
float finvW[3][3]
current inverse soft iron matrix
Definition: magnetic.h:76
#define THISBUILD
define build number sent in debug packet for display purposes only
float fRho
compass (deg)
float fV[3]
current hard iron offset x, y, z, (uT)
Definition: magnetic.h:75
#define F_6DOF_GY_KALMAN
6DOF accel and gyro (Kalman) algorithm selector - 0x2000 to include, 0x0000 otherwise ...
The sensor_fusion.h file implements the top level programming interface.
#define F_3DOF_G_BASIC
3DOF accel tilt (accel) algorithm selector - 0x0200 to include, 0x0000 otherwise
#define CHZ
uint8_t sUARTOutputBuffer[256]
main output buffer defined in control.c
Definition: control.c:59
volatile uint8_t DebugPacketOn
flag to enable debug packet
Definition: control.h:68
void CreateAndSendPackets(SensorFusionGlobals *sfg, uint8_t *sUARTOutputBuffer)
Called once per fusion cycle to stream information required by the NXP Sensor Fusion Toolbox...
#define MAX_ACCEL_CAL_ORIENTATIONS
number of stored precision accelerometer measurements
int16_t iBc[3]
averaged calibrated measurement (counts)
float fPhi
roll (deg)
#define CHX
Used to access X-channel entries in various data data structures.
Definition: sensor_fusion.h:76
float fFitErrorpc
current fit error %
Definition: magnetic.h:79
MagBuffer MagBuffer
mag cal constellation points
writePort_t * write
low level function to write a char buffer to the serial stream
Definition: control.h:72
volatile uint8_t RPCPacketOn
flag to enable roll, pitch, compass packet
Definition: control.h:69
Quaternion derived from 3-axis accel (tilt)
Definition: sensor_fusion.h:65
#define F_3DOF_Y_BASIC
3DOF gyro integration algorithm selector - 0x0800 to include, 0x0000 otherwise
#define F_6DOF_GB_BASIC
6DOF accel and mag eCompass algorithm selector - 0x1000 to include, 0x0000 otherwise ...
#define FUSION_HZ
(int) actual rate of fusion algorithm execution and sensor FIFO reads
Defines control sub-system.
int32_t index[MAGBUFFSIZEX][MAGBUFFSIZEY]
array of time indices
Definition: magnetic.h:66
void sBufAppendZeros(uint8_t *pDest, uint16_t *pIndex, uint16_t numZeros)
Definition: output_stream.c:92
float fB
current geomagnetic field magnitude (uT)
Definition: magnetic.h:77
#define F_USING_ACCEL
nominally 0x0001 if an accelerometer is to be used, 0x0000 otherwise
SensorFusionGlobals sfg
This is the primary sensor fusion data structure.
#define MAGBUFFSIZEY
y dimension in magnetometer buffer (12x24 equals 288 elements)
Definition: magnetic.h:45
float q2
y vector component
Definition: orientation.h:41
#define F_3DOF_B_BASIC
3DOF mag eCompass (vehicle/mag) algorithm selector - 0x0400 to include, 0x0000 otherwise ...
int32_t systick
systick timer;
Excluding SV_1DOF_P_BASIC, Any of the SV_ fusion structures above could be cast to type SV_COMMON for...
#define F_USING_MAG
Definition: magnetic.h:38
float q1
x vector component
Definition: orientation.h:40
int16_t iBs[3][MAGBUFFSIZEX][MAGBUFFSIZEY]
uncalibrated magnetometer readings
Definition: magnetic.h:65
#define RATERESOLUTION
Definition: output_stream.c:39
volatile quaternion_type QuaternionPacketType
quaternion type transmitted over UART
Definition: control.h:66
volatile uint8_t AngularVelocityPacketOn
flag to enable angular velocity packet
Definition: control.h:67